package master;

import java.net.*;
import java.io.*;
import java.util.StringTokenizer;

/**
 * @author erond
 */

/**
 * Classe per la creazione di un thread Client su multicast per lo scaricamento del file di stato xml di un gateway
 */
public class MulticastClient extends Thread{

	private InetAddress group = null;
	private int port = -1;
	private String nome_nodo_da_controllare = null;
	private int time = 0;
	private boolean loop = false;
	/**
	 * @return the loop
	 */
	public boolean isLoop() {
		return loop;
	}

	/**
	 * @param loop the loop to set
	 */
	public void setLoop(boolean loop) {
		this.loop = loop;
	}


	private boolean loop_flag = true;
	

	/**
	 * @param gatewayMulticast Indirizzo multicast del gateway dal quale scaricare l'xml
	 * @param gatewayPort porta sulla quale il gateway pubblica l'xml
	 * @param prefix prefisso per il nome del file xml che l'applicazione salverà in locale
	 * @param time Millisecondi da attendere nel caso di loop abilitato prima di ricominciare il ciclo di lettura
	 * @param loop Booleano che abilita/disabilita il ciclo continuo di scaricamento
	 */
	public MulticastClient(InetAddress gatewayMulticast, int gatewayPort, String prefix,int time, boolean loop) {
		group = gatewayMulticast;
		port = gatewayPort;
		nome_nodo_da_controllare = prefix;
		this.time=time;
		setLoop(loop);
	}

	/**
	 * Metodo invocato all'avvio del Thread
	 */
	public void run() {

		System.err.println("Multicast Client avviato...");

		boolean flag=true;
		boolean start=false;
		boolean xml_header=false;
		String linea_old = "";
		FileOutputStream file = null;
		PrintStream output = null;
		int count = 0;
		StringTokenizer st = null;
		String delim = "LINEE:";
		int numero_linee = 0;
		MulticastSocket socket = null;
		DatagramPacket packet = null;
		byte[] buf = new byte[256];
		ByteArrayInputStream biStream = null;
		DataInputStream diStream = null;
		String linea = null;

		try {
			socket = new MulticastSocket(port);
			packet = new DatagramPacket(buf,buf.length);
			System.out.println("Creata la socket: " + socket);
		} catch (IOException e){System.exit(3);}

		while(loop_flag) {

			count=0;

			try
			{
				socket.joinGroup(group); // adesione al gruppo associato
				System.out.println("Adesione al gruppo " + group.getHostAddress());
			} catch (IOException e){System.exit(4);}

			while (flag)
			{
				try
				{
					packet.setData(buf);
					socket.receive(packet);
				} catch (SocketTimeoutException te)
				{ System.out.println("Non ho ricevuto niente per 40 secondi, chiudo!");
				System.exit(4);
				} 
				catch (IOException e) { continue;}


				try {

					biStream = new ByteArrayInputStream(packet.getData(),0,packet.getLength());
					diStream = new DataInputStream(biStream);
					linea = diStream.readUTF();

					/**
					 * Controllo che il server multicast stia trasmettendo la prima linea.
					 * Di li in poi posso salvarmi la copia del xml con la garanzia
					 * che sia completo.
					 */
					if (!linea.isEmpty()) {

						if ((linea.contains("LINEE"))) {
							st=new StringTokenizer(linea);
							while(st.hasMoreTokens()) {
								String tmp=st.nextToken(delim);
								numero_linee = Integer.parseInt(tmp);
							}
						}

						if (linea.contains("<?xml")) {
							if (!linea.equals(linea_old)) {
								xml_header=false;
								if (!xml_header) {
									try {
										File f = new File(nome_nodo_da_controllare+"gateway.xml");
										if  (f.exists()) {
											f.delete();
										}
										//se il file con questo nome esiste già viene totalmente riscritto
										file = new FileOutputStream(nome_nodo_da_controllare+"gateway.xml");
										output = new PrintStream(file);
										output.println(linea);
										xml_header=true;
										count=1;
									} catch (FileNotFoundException e1) {
										e1.printStackTrace();
									}
								}
							}
						} else {

							if ((linea.trim().contains("<GATEWAY")) && (xml_header==true) && (!linea.equals(linea_old))) {
								start=true;
								output.println(linea);
								count++;
							}

							if (((start==true) && (!linea.trim().contains("<GATEWAY")) && (!linea.equals(linea_old)))) {
								output.println(linea);
								count++;
							}

							/**
							 * Controllo che non sia finito l'xml. Se è così concludo la ricezione uscendo dal ciclo.
							 */
							if ((linea.equalsIgnoreCase("</GATEWAY>"))&& (!linea.equals(linea_old)) || (linea.contains("<GATEWAY IP=\"\" />"))&& (!linea.equals(linea_old))) {
								if ((start==true)&&(count==(numero_linee))) {
									flag=false;
									start=false;
									xml_header=false;
									count=0;
									break;
								} else {
									System.err.println("MulticastClient: trovato </GATEWAY> ma start="+start+" e count="+count+" DIVERSO da numero_linee="+numero_linee);
								}
							}
						}
						linea_old=linea;
					} else System.err.println("Multicastclient: LINEA VUOTA...");

				} catch (IOException e) {
					System.out.println("MULTICASTCLIENT: eccezione!");
					e.printStackTrace();
					continue;
				}

			}//uscita dal while

			if (loop==false) loop_flag=false;
			else {try {Thread.sleep( time );} catch (Exception e) { continue; }}
		}

		// uscita dal gruppo e chiusura della socket
		System.out.println("\nUscita dal gruppo");
		try { socket.leaveGroup(group); }
		catch (IOException e) { System.out.println("Errore uscendo dal gruppo\n"); }

		socket.close();

	}//fine run


	/**
	 * @param args come parametri per l'eventuale lancio da console
	 */
	public static void main(String[] args) {

		MulticastClient after = null;
		MulticastClient before = null;
		
		try {
			after = new MulticastClient(InetAddress.getByName("230.0.0.1"), 65431, "after_", 1000, false);
		} catch (UnknownHostException e) {
			e.printStackTrace();
		}
		after.start();
		try {
			after.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		try {
			before = new MulticastClient(InetAddress.getByName("230.0.0.1"), 65433, "before_", 1000, false);
		} catch (UnknownHostException e) {
			e.printStackTrace();
		}
		before.start();
		try {
			before.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}


	} //fine main

} //fine classe

